package org.streets.commons.expression;

import java.util.HashMap;
import java.util.Map;

import org.streets.commons.util.StringUtils;


/**
 * 操作符
 *
 * @author dzb
 */
public class Operation {

	public InnerOperation op;

	public Operation(String op) {
		this.op = InnerOperation.createOperation(op);
	}

	public Object eval(EvalCommand leftCmd, EvalCommand rightCmd) {
		return op.eval(leftCmd, rightCmd);
	}

	public String toString() {
		return op.toString();
	}

	static abstract class InnerOperation {
		static Map<String, InnerOperation> opMap = new HashMap<String, InnerOperation>();
		static {
			opMap.put("&&", new And("&&"));
			opMap.put("||", new Or("||"));
			opMap.put("!", new Not("!"));
			opMap.put("==", new EQ("=="));
			opMap.put("!=", new NE("!="));
			opMap.put("<>", opMap.get("!="));
			opMap.put(">", new GT(">"));
			opMap.put(">=", new GE(">="));
			opMap.put("<", new LT("<"));
			opMap.put("<=", new LE("<="));
			opMap.put(":", new IN(":"));
		}

		public static InnerOperation createOperation(String op) {
			InnerOperation operation = opMap.get(op);
			if (operation == null) {
				throw new ParseException("不支持操作符：" + op);
			}
			return operation;
		}

		public boolean getBoolean(EvalCommand express) {
			Object value = express.evalValue();
			if (value instanceof Boolean) {
				return ((Boolean) value).booleanValue();
			}
			throw new ParseException("不能转换为boolean类型：" + value);
		}

		public float getNumber(EvalCommand express) {
			Object value = express.evalValue();
			if (value instanceof Number) {
				return ((Number) value).floatValue();
			}
			throw new ParseException("不能转换为number类型：" + value);
		}

		protected String op;

		private InnerOperation(String op) {
			this.op = op;
		}

		public abstract boolean eval(EvalCommand leftCmd, EvalCommand rightCmd);

		public String toString() {
			return op;
		}

		static class And extends InnerOperation {
			private And(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				return getBoolean(leftCmd) && getBoolean(rightCmd);
			}
		}

		static class Or extends InnerOperation {
			private Or(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				return getBoolean(leftCmd) || getBoolean(rightCmd);
			}
		}

		static class Not extends InnerOperation {
			private Not(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				// 无左操作数
				return !getBoolean(rightCmd);
			}
		}

		static class EQ extends InnerOperation {
			private EQ(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				Object v1 = leftCmd.evalValue();
				Object v2 = rightCmd.evalValue();
				if (v1 instanceof Number && v2 instanceof Number) {
					return ((Number) v1).floatValue() == ((Number) v2).floatValue(); 
				} else {
					return v1.equals(v2);
				}
			}
		}

		static class NE extends InnerOperation {
			private NE(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				Object v1 = leftCmd.evalValue();
				Object v2 = rightCmd.evalValue();
				if (v1 instanceof Number && v2 instanceof Number) {
					return ((Number) v1).floatValue() != ((Number) v2).floatValue(); 
				} else {
					return !v1.equals(v2);
				}
			}
		}

		static class GT extends InnerOperation {
			private GT(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				return getNumber(leftCmd) > getNumber(rightCmd);
			}
		}

		static class GE extends InnerOperation {
			private GE(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				return getNumber(leftCmd) <= getNumber(rightCmd);
			}
		}

		static class LT extends InnerOperation {
			private LT(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				return getNumber(leftCmd) < getNumber(rightCmd);
			}
		}

		static class LE extends InnerOperation {
			private LE(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				return getNumber(leftCmd) <= getNumber(rightCmd);
			}
		}
		// 添加In操作 可以用":"代替
		static class IN extends InnerOperation {
			private IN(String op) {
				super(op);
			}

			public boolean eval(EvalCommand leftCmd, EvalCommand rightCmd) {
				String lv = (String)leftCmd.evalValue();
				String rv = (String) rightCmd.evalValue();
				if (rv.indexOf("]") > 0) {
					rv = StringUtils.substringBetween(rv, "[", "]");
				}
				String[] rvs = rv.split(",");
				for (String v : rvs) {
					if (lv.equals(v.trim())) {
						return true;
					}
				}
				return false;
			}			
		}
	}
}
